#pragma once
#include<iostream>
#include<queue>
#include<pthread.h>

template<class T>
class BlockQueue
{
    public:
    BlockQueue(int cap=10)
    :_cap(cap)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_pcond,nullptr);
        pthread_cond_init(&_ccond,nullptr);
    }
    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_pcond);
        pthread_cond_destroy(&_ccond);
    }
    bool Empty()
    {
        return _blockqueue.empty();
    }
    bool IsFull()
    {
        return _cap==_blockqueue.size();
    }
    //生产者调用
    void Equeue(T& in)
    {
        pthread_mutex_lock(&_mutex);
        loop_prstart:
        if(!IsFull())
        {
            _blockqueue.push(in);
            if(consum_slnum>0)
            {
                pthread_cond_signal(&_ccond);
            }
        }
        else
        {
            produce_slnum++;
            pthread_cond_wait(&_pcond, &_mutex); 
            produce_slnum--;
            goto loop_prstart;
        }
        pthread_mutex_unlock(&_mutex);
    }
    //消费者调用
    void PopQueue(T* out)
    {
        pthread_mutex_lock(&_mutex);
        loop_crstart:
        if(!Empty())
        {
            *out=_blockqueue.front();
            _blockqueue.pop();
            if(produce_slnum>0)
            {
                pthread_cond_signal(&_pcond);
            }
        }
        else
        {
            consum_slnum++;
            pthread_cond_wait(&_ccond, &_mutex); 
            consum_slnum--;
            goto loop_crstart;
        }
        pthread_mutex_unlock(&_mutex);
    }
    private:
    std::queue<T> _blockqueue;
    size_t _cap;
    size_t consum_slnum=0;
    size_t produce_slnum=0;
    pthread_mutex_t _mutex;
    pthread_cond_t _pcond;
    pthread_cond_t _ccond;
};